package com.xuecheng.media.service.jobhandler;

import cn.hutool.crypto.digest.DigestUtil;
import com.xuecheng.base.utils.Mp4VideoUtil;
import com.xuecheng.media.model.po.MediaProcess;
import com.xuecheng.media.service.MediaFileService;
import com.xuecheng.media.service.MediaProcessService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @description 测试执行器
 * @author Mr.M
 * @date 2022/9/13 20:32
 * @version 1.0
 */
 @Component
 @Slf4j
public class VideoTask {

  @Resource
  private MediaProcessService mediaProcessService;

  @Resource
  private MediaFileService mediaFileService;

  @Value("${videoprocess.ffmpegpath}")
  private String ffmpegpath;


 /**
  * 1、简单任务示例（Bean模式）
  */
/* @XxlJob("testJob")
 public void testJob() throws Exception {
  log.info("开始执行.....");

 }*/

 /**
  * 视频转码任务
  */
 @XxlJob("videoJobHandler")
 public void videoJobHandler() throws Exception {

  // 分片参数
  int shardIndex = XxlJobHelper.getShardIndex();
  int shardTotal = XxlJobHelper.getShardTotal();

  log.info("分片参数：当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
  log.info("开始执行第"+shardIndex+"批任务");
  //拉取待执行视频转码任务列表
  //获取cpu的核心数
  int limit = Runtime.getRuntime().availableProcessors();
  List<MediaProcess> fileProcessTask = mediaProcessService.getFileProcessTask(shardTotal, shardIndex,limit);
  //获取任务数
  int taskNum = fileProcessTask.size();
  if (taskNum <= 0) {
   log.debug("没有任务");
   return;
  }
  //创建线程池
  ExecutorService executorService = Executors.newFixedThreadPool(taskNum);
  //创建计时器
  CountDownLatch countDownLatch = new CountDownLatch(taskNum);
  //遍历执行任务
  fileProcessTask.forEach(task->{
   //将任务加入到线程池执行
   executorService.execute(()->{
    try {
     Long taskId = task.getId();
     //开启任务执行
     boolean res = mediaProcessService.startTask(taskId);
     //若该任务正在执行则跳过该任务
     if (!res) {
      log.error("抢占任务失败！,任务id:{}",task);
      return;
     }
     //====================================视频转码===========================================
     //从minion下载源文件
     File OriginFile = mediaFileService.downloadFileFromMinIO(task.getBucket(), task.getFilePath());
     String taskFileId = task.getFileId();
     if (OriginFile == null||!DigestUtil.md5Hex(OriginFile).equals(taskFileId)) {
      log.error("下载源视频出错，任务Id:{},fileId:{}",taskId,taskFileId);
      mediaProcessService.saveProcessFinishStatus(taskId,"3", taskFileId,null,"下载源视频出错");
      return;
     }
     //ffmpeg的路径
     String ffmpeg_path = ffmpegpath;//ffmpeg的安装位置
     //源avi视频的路径
     String video_path = OriginFile.getAbsolutePath();
     //转换后mp4文件的名称
     String mp4_name = taskFileId+".mp4";
     //创建临时文件，存储转换后的文件
     File tempFile = null;
     try {
      tempFile= File.createTempFile("minio", ".mp4");
     } catch (IOException e) {
      log.error("创建临时文件失败");
      mediaProcessService.saveProcessFinishStatus(taskId,"3", taskFileId,null,"创建临时文件失败");
      return;
     }
     //转换后mp4文件的路径
     String mp4_path = tempFile.getAbsolutePath();
     //创建工具类对象
     Mp4VideoUtil videoUtil = new Mp4VideoUtil(ffmpeg_path,video_path,mp4_name,mp4_path);
     //开始视频转换，成功将返回success
     String s = videoUtil.generateMp4();
     if (!s.equals("success")){
      log.error("视频转码失败,taskId:{},fileId:{}",taskId,taskFileId);
      mediaProcessService.saveProcessFinishStatus(taskId,"3", taskFileId,null,"视频转码失败");
      return;
     }
     //===========================================转码成功 将转码视频上传minio=============================================
     String bucket = task.getBucket();
     String objectName = task.getFilePath();
     //替换后缀名
     objectName = objectName.replace(".avi", ".mp4");
     boolean b = mediaFileService.addMediaFilesToMinIO(tempFile.getAbsolutePath(), "video/mp4", bucket, objectName);
     if (!b){
      log.error("上传转码视频失败,taskId:{},fileId:{}",taskId,taskFileId);
      mediaProcessService.saveProcessFinishStatus(taskId,"3", taskFileId,null,"上传转码视频失败");
      return;
     }
     //=========================================上传成功 更新该转码任务的状态=============================================
     mediaProcessService.saveProcessFinishStatus(taskId,"2", taskFileId,getMergeFilePath(taskFileId,".mp4"),null);
    } finally {
     //计数器减一
     countDownLatch.countDown();
    }
   });
  });
  //阻塞，直到所有线程执行完毕方法才结束(设置过期时间，兜底策略)
  countDownLatch.await(30, TimeUnit.MINUTES);
 }

 private String getMergeFilePath(String fileMd5,String fileExt) {
  return fileMd5.charAt(0)+"/"+ fileMd5.charAt(1)+"/"+fileMd5+"/"+fileMd5+fileExt;
 }


}
